/*
 * CS_REQ_FAIRY_COMBINE.cpp
 *
 *  Created on: 2014. 4. 29.
 *      Author: mega
 */

#include "../../User.h"
#include "../../Command.h"
#include "../../GameLog.h"
#include "../../NLogic/Bag.h"
#include "../../NLogic/Equip.h"
#include "../../NLogic/Function.h"
#include "../../NResource/Static.h"

namespace ProjectZ { namespace NCommand {

static void RecoveryItem(std::vector<NLogic::Item *> & clsItemVector, NLogic::Bag * pBag)
{
	// Bag에서 아이템을 꺼냈기 때문에 만약 에러가 발생하는 경우 다시 Bag으로 넣어준다.
	std::for_each(clsItemVector.begin(), clsItemVector.end(), [&](NLogic::Item * pItem) {
		pBag->AddItem(pItem);
	});
}

static void SendFailFairyCombine(User * pUser, int ack)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<int16_t>(ack);
	pAck->MakePacket(CMD_SC_REQ_FAIRY_COMBINE);
	pUser->Send(pAck);
}

void Command::CS_REQ_FAIRY_COMBINE(User * pUser, ::Network::Packet * pPacket)
{
/*	CS_REQ_FAIRY_COMBINE		0x150c
	{
		u8	count;		// max 6
		{
			u64 u64item_seq;
		}
	}

	SC_REQ_FAIRY_COMBINE		0x150d
	{
		s16       u16ack;			// ACK_NOT_ENOUGH_GOLD : 골드부족 , ???: 페어리 최대레벨 도달로 합성불가
		u8	  resultType;			// 1: 성공, 2: 대성공 3:초대성공
	}*/

	PREPARE_PACKET;

	uint8_t count = 0;
	uint64_t fairySeq = 0;

	*pPacket >> fairySeq >> count;

	if (1 > count || count > 6)
	{
		DEBUGLOG("%s : INVALID COUNT=%d", __FUNCTION__, count);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Bag * pBag = pUser->GetBag(BAG_TYPE_FAIRY);
	if (NULL == pBag)
	{
		DEBUGLOG("%s : pBag is NULL!!", __FUNCTION__);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Item * pFairy = pBag->GetItem(fairySeq);
	if (NULL == pFairy)
	{
		DEBUGLOG("%s : pFairy is NULL!!", __FUNCTION__);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	// 최대 레벨 = 등급에 따라 결정 (등급 * 10)
	int maxLevel = (pFairy->GetData().quality + 1) * 10;

	if (pFairy->GetData().level >= maxLevel)
	{
		DEBUGLOG("%s : Fairy is already MAX!!", __FUNCTION__);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Equip * pEquip = pUser->GetEquip();
	if (NULL == pEquip)
	{
		DEBUGLOG("%s : pEquip is NULL!!", __FUNCTION__);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	NLogic::Item * pEquipFairy = pEquip->GetItem(ITEM_EQUIP_POS_FAIRY);
	if (NULL == pEquipFairy)
	{
		DEBUGLOG("%s : pEquipFairy is NULL!!", __FUNCTION__);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	if (pEquipFairy->GetItemSeq() == pFairy->GetItemSeq())
	{
		DEBUGLOG("%s : BASE EQUIP FAIRY!!!", __FUNCTION__);
		SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
		return;
	}

	int exp = 0;
	std::vector<NLogic::Item *> clsItemVector;

	for (int i = 0; i < count; i++)
	{
		uint64_t itemSeq = 0;

		*pPacket >> itemSeq;

		NLogic::Item * pItem = pBag->PopItem(itemSeq);
		if (NULL == pItem)
		{
			DEBUGLOG("%s : pItem is NULL, itemSeq=%lld", __FUNCTION__, itemSeq);
			RecoveryItem(clsItemVector, pBag);
			SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
			return;
		}

		if (pEquipFairy->GetItemSeq() == pItem->GetItemSeq())
		{
			DEBUGLOG("%s : EQUIP FAIRY!!!", __FUNCTION__);
			RecoveryItem(clsItemVector, pBag);
			SendFailFairyCombine(pUser, ACK_UNKNOWN_ERROR);
			return;
		}

		clsItemVector.push_back(pItem);

		// 재료 페어리 경험치 = 등급^2 * 레벨 / 2
		exp += pow(pItem->GetData().quality + 1, 2) * pItem->GetData().level / 2;

		DEBUGLOG("%s : Quality=%d, Level=%d, TotalExp=%d", __FUNCTION__, pItem->GetData().quality, pItem->GetData().level, exp);
	}

	// 소모 골드 계산
	// 경험치 1당 2000 골드 소모
	int needGold = exp * 2000;
	if (needGold > static_cast<int>(pUser->GetCharacterInfo().gold))
	{
		DEBUGLOG("%s : Not Enought Gold", __FUNCTION__);
		RecoveryItem(clsItemVector, pBag);
		SendFailFairyCombine(pUser, ACK_NOT_ENOUGH_GOLD);
		return;
	}

	int succType = NResource::Static::Instance().GetFairyCombineResource()->GetSuccessType(exp);

	int prevLevel = pFairy->GetData().level;

	// 레벨업 시 속성값 재 계산
	// (속성값 / 전 레벨) * 현 레벨
	if (true == NLogic::NFunction::IncreaseExpFairy(pFairy, exp, maxLevel))
	{
		for (int i = 1; i <= 5; i++)
		{
			int value = pFairy->GetData().eff_value[i] / prevLevel;

			if (0 >= value)
			{
				pFairy->GetData().eff_value[i] += 1;
			}
			else
			{
				pFairy->GetData().eff_value[i] = value * pFairy->GetData().level;
			}
		}
	}

	DEBUGLOG("%s : Total Increase Exp=%d", __FUNCTION__, exp);

	if (false == pFairy->UpdateDatabaseItemInfo())
	{
		DEBUGLOG("%s : FAIRY UPDATE FAIL", __FUNCTION__);
		RecoveryItem(clsItemVector, pBag);
		SendFailFairyCombine(pUser, ACK_DB_ERROR);
		return;
	}

	// 재료 페어리 삭제 처리
	std::for_each(clsItemVector.begin(), clsItemVector.end(), [&](NLogic::Item * pItem) {
		pItem->DeleteDatabaseItemInfo(NLogic::Item::ItemStatus::EM_ITEM_STATUS_FAIRY_COMBINE);
	});
	clsItemVector.clear();

	// 응답
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<int16_t>(ACK_OK);
	*pAck << static_cast<uint8_t>(succType);
	pAck->MakePacket(CMD_SC_REQ_FAIRY_COMBINE);
	pUser->Send(pAck);

	// 골드 차감
	NLogic::NFunction::ModifyGold(pUser, (needGold * -1));
	NGameLog::LogGoldInfo(pUser, FAIRY_COMBINE, (needGold * -1));
}

} /* NCommand */ } /* ProjectZ */
